﻿#include"stdafx.h"
#ifdef LK_WINDOWS_UI_CONTROL_
#ifdef _VC
#pragma comment(lib,"Comctl32.lib")
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif

namespace LK
{
	namespace Windows
	{
		namespace UI
		{
			void PControl::AddTypeInfo()
			{
#ifdef LK_REFLECTION_
				//引用反射命名空间
				using namespace Reflection;
				//获取类库的引用
				PTypeLibrary lib = GetGlobleLibrary();
				//获取类库中的全局命名空间
				PNamespaceNode globle = lib.GetGlobleNamespaceRef();
				//添加LK命名空间
				PNamespaceNode space = globle.FindOrAddNamespace(L"LK.Windows.UI");
				//在UI命名空间中添加PControl类型
				PTypeNode n = space.FindOrAddTypeNode(L"PControl", PType::Make<PControl>());
				//设置基类
				n.AddBaseType(PType::Make<PObject>());
#endif
			}

			void IControl::Initial()
			{
#ifdef _VC
				// 如果一个运行在 Windows XP 上的应用程序清单指定要
				// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式，
				//则需要 InitCommonControlsEx()。  否则，将无法创建窗口。
				INITCOMMONCONTROLSEX InitCtrls;
				InitCtrls.dwSize = sizeof(InitCtrls);
				// 将它设置为包括所有要在应用程序中使用的
				// 公共控件类。
				InitCtrls.dwICC = ICC_WIN95_CLASSES;
				InitCommonControlsEx(&InitCtrls);
#endif
			}
			//句柄到控件实例的映射（已弃用）
			//std::map<void*,IControl*> IControl::hMap;
			//线程同步
			Mutex& IControl::hMaptc()
			{
				static Mutex tc;
				return tc;
			}
			//指针传递
			IControl* IControl::staticPointer = NULL;
			//静态的全局消息处理
			LRESULT CALLBACK IControl::StaticWndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
			{
				IControl*p = GetPointerByHandle(hWnd);
				if (!p&&hMaptc().GetID() == GetCurrentThreadId())
				{
					p = staticPointer;
					p->SetHandle(hWnd);
					staticPointer = NULL;
				}
				if (p)
				{
					MSG msg;
					msg.hwnd = hWnd;
					msg.message = iMessage;
					msg.lParam = lParam;
					msg.wParam = wParam;
					msg.pt.x = msg.pt.y = 0;
					msg.time = 0;
					p->WndProc(msg);
					switch (iMessage)
					{
#ifdef LK_FUNCTIONAL_ACTION_//委托模型
					case WM_SYSKEYUP:
						if (!p->KeyUp.IsNull())
						{
							p->tc.Lock();
							LK::Functional::PDelegate<void(KeyEventArgs&)> xd = p->KeyUp;
							p->tc.UnLock();
							KeyEventArgs e;
							e.Alt = true;
							e.Control = e.Shift = e.Handled = false;
							e.KeyValue = (DWORD)wParam;
							e.RepeatCount = lParam & 0xffff;
							xd.Invoke(e);
							if (e.Handled)return 0;
						}
						break;
					case WM_KEYUP:
						if (!p->KeyUp.IsNull())
						{
							p->tc.Lock();
							LK::Functional::PDelegate<void( KeyEventArgs&)> xd = p->KeyUp;
							p->tc.UnLock();
							KeyEventArgs e;
							e.Control = e.Shift = e.Alt = e.Handled = false;
							e.KeyValue = (DWORD)wParam;
							e.RepeatCount = lParam & 0xffff;
							xd.Invoke(e);
							if (e.Handled)return 0;
						}
						break;
					case WM_SYSKEYDOWN:
						if (!p->KeyDown.IsNull())
						{
							p->tc.Lock();
							LK::Functional::PDelegate<void( KeyEventArgs&)> xd = p->KeyDown;
							p->tc.UnLock();
							KeyEventArgs e;
							e.Alt = true;
							e.Control = e.Shift = e.Handled = false;
							e.KeyValue = (DWORD)wParam;
							e.RepeatCount = lParam & 0xffff;
							xd.Invoke(e);
							if (e.Handled)return 0;
						}
						break;
					case WM_KEYDOWN:
						if (!p->KeyDown.IsNull())
						{
							p->tc.Lock();
							LK::Functional::PDelegate<void( KeyEventArgs&)> xd = p->KeyDown;
							p->tc.UnLock();
							KeyEventArgs e;
							e.Control = e.Shift = e.Alt = e.Handled = false;
							e.KeyValue = (DWORD)wParam;
							e.RepeatCount = lParam & 0xffff;
							xd.Invoke(e);
							if (e.Handled)return 0;
						}
						break;
					case WM_USER://消息
						if (lParam == WM_USER&&wParam == 0&&!p->syncActions.IsNull())
						{
							p->tc.Lock();
							LK::Functional::PActions x = p->syncActions[0];
							p->syncActions.RemoveAt(0);
							p->tc.UnLock();
							x.Do();
							return 0;
						}
						else if (wParam == WM_USER && lParam == 0&&!p->action.IsNull())
						{
							p->action.Do();
							p->tc.Lock();
							p->action.SetToNull();;
							p->tc.UnLock();
							return 0;
						}
						break;
#endif
					case WM_COMMAND:
						{
							IControl*pp = GetPointerByHandle(HWND(lParam));
							bool Handled = false;
							if(pp)switch (wParam)
							{
							case BN_CLICKED:
#ifdef LK_FUNCTIONAL_ACTION_//委托模型
								if (!pp->Click.IsNull())
								{
									pp->tc.Lock();
									LK::Functional::PDelegate<void()> xd = pp->Click;
									pp->tc.UnLock();
									xd.Invoke();
								}
#endif
								break;
							}
							if (Handled)return 0;
						}
						break;
					case WM_CLOSE:
						if (p->OnCancel())msg.message = 0;break;
					case WM_PAINT:
						p->OnPaint();break;
					default:break;
					}
					return p->DefWndProc(msg);
				}
				else
				{
					Throw<PPointerIsNullException>();
				}
				return DefWindowProcW(hWnd, iMessage, wParam, lParam);
			}
			//消息处理程序
			void IControl::WndProc(MSG& ){}
			LRESULT IControl::DefWndProc(MSG& message)
			{
				return DefWindowProcW(message.hwnd, message.message, message.wParam, message.lParam);//默认的处理方式
			}
			//默认处理方式
			WNDCLASSEXW& IControl::Design()
			{
				static ATOM atom;
				static WNDCLASSEXW wndclass;
				if (!atom){
					wndclass.cbSize = sizeof(WNDCLASSEXW);
					wndclass.style = CS_HREDRAW | CS_VREDRAW;
					wndclass.lpfnWndProc = StaticWndProc;
					wndclass.cbClsExtra = 0;
					wndclass.cbWndExtra = 0;
					wndclass.hInstance = GetCurrentInstance();
					wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
					wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
					wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
					wndclass.lpszMenuName = NULL;
					wndclass.lpszClassName = L"IControl";
					wndclass.hIconSm = NULL;
					atom = RegisterClassExW(&wndclass);
				}
				return wndclass;
			}
			HWND IControl::Create(LPCWSTR text, Rect const&position, LPCWSTR className, DWORD dwStyle, DWORD dwExStyle, HWND hParent, HMENU hMenu)
			{
				HWND h = CreateWindowExW(dwExStyle, className, text, dwStyle,
					position.point.x, position.point.y, position.size.width, position.size.height, hParent,
					hMenu, GetModuleHandleW(NULL), NULL);
				if(!h)throw PWindowsException(GetLastError());
				return h;
			}
			void IControl::Run()
			{
				if (GetCurrentThreadId() != GetThreadId())throw LK::Windows::PWindowsException(E_ACCESSDENIED);//线程错误
				MSG msg;
				ShowWindow(GetHandle(), SW_SHOWDEFAULT);//显示窗体
				UpdateWindow(GetHandle());//更新窗体
				while (GetMessageW(&msg, NULL, 0, 0) == 1)
				{
					TranslateMessage(&msg);
					DispatchMessageW(&msg);
				}
			}
#ifdef LK_FUNCTIONAL_ACTION_//委托模型
			//同步调用
			void IControl::Invoke(LK::Functional::PActions const& act)
			{
				this->action = act;
				SendMessageW(hWnd, WM_USER, WM_USER, 0);
			}
			//异步调用
			void IControl::BeginInvoke(LK::Functional::PActions const& act)
			{
				tc.Lock();
				if (syncActions.IsNull())syncActions = new LK::Collection::List<LK::Functional::PActions>(0);
				syncActions.Append(act);
				tc.UnLock();
				PostMessageW(hWnd, WM_USER, 0, WM_USER);
			}
#endif
			PString IControl::GetText()const
			{
				int len = GetWindowTextLengthW(hWnd);
				LPWSTR p = Memory::New<WCHAR>(len + 1);
				len = GetWindowTextW(hWnd, p, len + 1);
				return new String(len, p, 0);
			}
			void IControl::SetText(PString const&s)
			{
				SetWindowTextW(hWnd, s);
			}
			void IControl::SetMaxPosition(Point const& size)
			{
				WINDOWPLACEMENT pm = { 0 };
				pm.length = sizeof(WINDOWPLACEMENT);
				if (GetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
				pm.ptMaxPosition.x = size.x;
				pm.ptMaxPosition.y = size.y;
				if (SetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
			}
			::LK::Drawing::Point<int> IControl::GetMaxPosition()const
			{
				WINDOWPLACEMENT pm = { 0 };
				pm.length = sizeof(WINDOWPLACEMENT);
				if (GetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
				return Point(pm.ptMaxPosition.x, pm.ptMaxPosition.y);
			}
			void IControl::SetMinPosition(Point const& size)
			{
				WINDOWPLACEMENT pm = { 0 };
				pm.length = sizeof(WINDOWPLACEMENT);
				if (GetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
				pm.ptMinPosition.x = size.x;
				pm.ptMinPosition.y = size.y;
				if (SetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
			}
			::LK::Drawing::Point<int> IControl::GetMinPosition()const
			{
				WINDOWPLACEMENT pm = { 0 };
				pm.length = sizeof(WINDOWPLACEMENT);
				if (GetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
				return Point(pm.ptMinPosition.x, pm.ptMinPosition.y);
			}
			void IControl::SetState(UINT s)const
			{
				WINDOWPLACEMENT pm = { 0 };
				pm.length = sizeof(WINDOWPLACEMENT);
				if (GetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
				pm.showCmd = s;
				if (SetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
			}
			UINT IControl::GetState()const
			{
				WINDOWPLACEMENT pm = { 0 };
				pm.length = sizeof(WINDOWPLACEMENT);
				if (GetWindowPlacement(hWnd, &pm) == false)throw PWindowsException(GetLastError());//获取信息失败
				return pm.showCmd;
			}
			void IControl::SetRect(const Rect&r)
			{
				if (SetWindowPos(hWnd, NULL, r.point.x, r.point.y, r.size.width, r.size.height, 0) == 0)throw PWindowsException(GetLastError());
			}
			::LK::Drawing::Rect<int> IControl::GetRect()const
			{
				::RECT rect;
				if (GetWindowRect(hWnd, &rect) == 0)throw PWindowsException(GetLastError());
				return rect;
			}
			void IControl::SetClientSize(const Size&r)
			{
				::RECT rect;
				::RECT rectw;
				if (::GetClientRect(hWnd, &rect) == 0)throw PWindowsException(GetLastError());
				if (GetWindowRect(hWnd, &rectw) == 0)throw PWindowsException(GetLastError());
				if (SetWindowPos(hWnd, NULL, rectw.left, rectw.top, rectw.right - rectw.left + r.width - rect.right+ rect.left, rectw.bottom - rectw.top+ r.height - rect.bottom+ rect.top, 0) == 0)throw PWindowsException(GetLastError());
			}
			::LK::Drawing::Size<int> IControl::GetClientSize()const
			{
				::RECT rect;
				if (::GetClientRect(hWnd, &rect) == 0)throw PWindowsException(GetLastError());
				return Size(rect.right, rect.bottom);
			}
			index_t IControl::GetTextLength()const
			{
				return GetWindowTextLengthW(hWnd);
			}
			void IControl::SetFont(HFont const&hf)
			{
				SendMessageW(hWnd, WM_SETFONT, (WPARAM)(HFONT)hf, TRUE);
			}
			HFont IControl::GetFont()const
			{
				return (HFONT)SendMessageW(hWnd, WM_GETFONT, 0, 0);
			}
			bool IControl::IsVisible()const
			{
				return IsWindowVisible(hWnd)!=0;
			}
		}
	}
}
#endif
